<?php
/**
 * Crc CMS
 *
 * @category   Crc
 * @package    Plugins
 * @author     Moldovan Calin <mcalin45@gmail.com>
 * @author     Vlad Razvan <razvanvlad1982@yahoo.com>
 * @copyright  Copyright (c) 2012
 * @version    $Id: Acl.php 54 2012-10-02 15:41:20Z mcalin45@gmail.com $
 */


/**
 * Class for the ACL plugin.
 *
 * @category   Crc
 * @package    Plugins
 * @author     Moldovan Calin <mcalin45@gmail.com>
 * @author     Vlad Razvan <razvanvlad1982@yahoo.com>
 * @copyright  Copyright (c) 2012
 */
class Plugins_Acl extends Zend_Controller_Plugin_Abstract
{

	/**
	 * ACL object
	 *
	 * @var Zend_Acl
	 **/
	protected $_acl;

	/**
	 * The user's role name
	 *
	 * @var string
	 **/
	protected $_roleName;

	/**
	 * The ident id from DB
	 *
	 * @var int
	 */
	protected $_idIdentity;

    /**
     * The default role if the user is not logged in
     *
     * @var int
     */
	const USER_DEFAULT_GUEST = 'Guest';

    /**
     * dispatchLoopStartup
     *
     * Setting the user role
     * If the user is logged in the role is set from the user object
     * If the user is not logged in the the default user rol is set
     *
     * @return void
     */
	public function dispatchLoopStartup()
    {
		$users = new Application_Model_Collection_User();
		$roles = new Application_Model_Collection_AclRole();

		if (Zend_Auth::getInstance()->hasIdentity())
		{
			$user = $users->find(Zend_Auth::getInstance()->getIdentity()->id)->current();

			// Check status for current user
			if ($user->getStatus() == 1)
			{
				$role = $roles->find($user->getIdAclRole())->current();
				$this->_roleName = $role->getName();
			}
			else
			{
				$this->_roleName = self::USER_DEFAULT_GUEST;
				Zend_Auth::getInstance()->clearIdentity();
			}
		}
		else
		{
			$this->_roleName = self::USER_DEFAULT_GUEST;
		}

		Zend_Registry::set('currentRoleName', $this->_roleName);
		$this->_populateAcl();
	}

	/**
	 * Populate the ACL object
     * If there is a cache for user's role then we build the object from the cache
     * If there isn't a cache then we build the object from the database
	 *
	 * @param string $roleName
	 * @param Models_AlcRights $modelRights
	 * @return void
	 */
	protected function _populateAcl()
    {
		$cache = Zend_Registry::get('Zend_Cache_Core');
		if (($this->_acl = $cache->load('ACL_rights')) === false )
        {
			$this->_acl = new Zend_Acl();
			$aclRights = new Application_Model_Collection_AclRight();
			$aclRoles = new Application_Model_Collection_AclRole();
			$aclResources = new Application_Model_Collection_AclResource();

			$resources = $aclResources->getResourcesForAcl();
			foreach ($resources as $resource => $parent)
			{
                if ($parent)
                {
                    $this->_acl->add(new Zend_Acl_Resource($resource),  $parent);
                }
                else
                {
                    $this->_acl->add(new Zend_Acl_Resource($resource));
                }
			}

			$roles = $aclRoles->getRolesForAcl();
			foreach ($roles as $role)
			{
				if ($role->getParent())
				{
					$this->_acl->addRole(new Zend_Acl_Role($role->getName()), $role->getParent());
				}
				else
				{
					$this->_acl->addRole(new Zend_Acl_Role($role->getName()));
				}

				$rights = $aclRights->getRoleRightsForAcl($role);
				foreach ($rights as  $resource => $permision)
				{
					if ($permision)
					{
						$this->_acl->allow($role->getName(), $resource);
					}
					else
					{
						$this->_acl->deny($role->getName(), $resource);
					}
				}
			}
			$cache->save($this->_acl, 'ACL_rights');
		}
		Zend_Registry::set('acl', $this->_acl);
	}

	/**
	 * Set the ACL object
	 *
	 * @param Zend_Acl $aclData
	 * @return void
	 **/
	public function setAcl(Zend_Acl $aclData)
    {
		$this->_acl = $aclData;
	}

	/**
	 * Get the ACL object
	 *
	 * @return Zend_Acl
	 **/
	public function getAcl()
    {
		return $this->_acl;
	}

	/**
	 * Set the roleName for the ACL
	 *
	 * @param string $roleName
	 * @return none
	 **/
	public function setRoleName($roleName)
    {
		$this->_roleName = $roleName;
	}

	/**
	 * Get the roleName from the ACL
	 *
	 * @return string $roleName
	 **/
	public function getRoleName()
    {
		return $this->_roleName;
	}

	/**
	 * preDispatch
     *
     * Check if the current role has rights for the request
     * If he doesn't have rights and the user is Guest (not logged in) then the login page is displayed
     * If he is logged in the he is forworded to the deny page
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @return void
	 **/
	public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        if (!$this->isRequestAllowed($request))
        {
            if($this->isLoginNeeded($request))
            {
                $this->redirectToLogin();
            }
            else
            {
                $this->denyAccess($request);
            }
        }
	}

	/**
	 * Check if the current role has rights for a request
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @return boolean
	 */
	public function isRequestAllowed(Zend_Controller_Request_Abstract $request)
    {
        try
        {
            $module = $request->getModuleName();
            $controller = $request->getControllerName();
            $action = $request->getActionName();

            if ($this->_acl->has($module . ':' . $controller . ':' . $action))
            {
                if ($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller . ':' . $action))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                if ($this->_acl->has($module . ':' . $controller))
                {
                    if ($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller))
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    if ($this->_acl->has($module))
                    {
                        if ($this->_acl->isAllowed($this->_roleName, $module))
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }
        catch (Zend_Acl_Exception $e)
        {
            return false;
        }
	}


	/**
	 * Action for deny page
	 *
	 * @return void
	 **/
	public function denyAccess(Zend_Controller_Request_Abstract $request)
    {
        $this->getResponse()->setRedirect('/');
	}

    /**
     * Check if login is needed
     *
     *
     * @return void
     **/
	public function isLoginNeeded(Zend_Controller_Request_Abstract $request)
    {
        $module = $request->getModuleName();
        $controller = $request->getControllerName();
        $action = $request->getActionName();

        $resource = $module . ':' . $controller . ':' . $action;
        if ($this->_acl->has($resource))
        {
            return !Zend_Auth::getInstance()->hasIdentity();
        }
        else
        {
            return false;
        }
	}

	/**
	 * Action for login page
	 *
	 * @return void
	 **/
	public function redirectToLogin()
    {
        $this->getResponse()->setRedirect('/user/index/login');
	}
}